package bookhive.catalog;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;

import net.jxta.discovery.DiscoveryService;
import net.jxta.exception.PeerGroupException;
import net.jxta.id.ID;
import net.jxta.id.IDFactory;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.protocol.ModuleImplAdvertisement;
import net.jxta.protocol.PeerGroupAdvertisement;
import net.jxta.rendezvous.RendezVousService;

import bookhive.PeerLauncher;
import bookhive.datastructures.catalog.CatalogGroupInfo;

public class CatalogLauncher extends PeerLauncher {

	private String catalogPeerName;

	public CatalogLauncher(String[] args) {

		super(new File("config/catalog.config"));

		File networkConfigFile = new File("config/network.config");
		Properties p = new Properties();
		try {
			p.load(new FileInputStream(networkConfigFile));
		} catch (Exception e) {
			e.printStackTrace();
		}

		HttpConfig(p, args);
		TcpConfig(p, args);

		String relayMaxClient = p.getProperty("relayMaxClient");
		if (relayMaxClient != null) {
			netconfig.setRelayMaxClients(Integer.parseInt(relayMaxClient));
		} else
			netconfig.setRelayMaxClients(0);

		netconfig.setName(catalogPeerName);

		catalogPeerName = catalogProps.getProperty("PeerName");
		if (catalogPeerName == null)
			catalogPeerName = String.valueOf(Math.random());
	}

	private void HttpConfig(Properties p, String[] args) {
		try {
			/*
			 * Default httpPort is 9901
			 */
			String httpPort = p.getProperty("httpPort");
			if (httpPort != null) {
				netconfig.setHttpPort(Integer.parseInt(httpPort));
			} else
				netconfig.setHttpPort(9901);

			/*
			 * Default httpAddress is passed by command line
			 */
			String httpAddress = p.getProperty("httpAddress");
			if (httpAddress != null) {
				netconfig.setHttpInterfaceAddress(httpAddress);
			} else {
				netconfig.setHttpInterfaceAddress(args[0]);
			}

			netconfig.setHttpEnabled(true);
			netconfig.setHttpOutgoing(true);

			/*
			 * Default httpIncoming is false;
			 */
			String httpIncoming = p.getProperty("httpIncoming");
			if (httpIncoming != null) {
				netconfig.setHttpIncoming(Boolean.valueOf(httpIncoming));
			} else {
				netconfig.setHttpIncoming(Boolean.valueOf(false));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void TcpConfig(Properties p, String[] args) {
		try {
			/*
			 * Default httpPort is 9701
			 */
			String tcpPort = p.getProperty("tcpPort");
			if (tcpPort != null) {
				netconfig.setTcpPort(Integer.parseInt(tcpPort));
			} else
				netconfig.setTcpPort(9701);

			/*
			 * Default httpAddress is passed by command line
			 */
			String tcpAddress = p.getProperty("tcpAddress");
			if (tcpAddress != null) {
				netconfig.setTcpInterfaceAddress(tcpAddress);
			} else {
				netconfig.setTcpInterfaceAddress(args[0]);
			}

			netconfig.setTcpEnabled(true);
			netconfig.setTcpOutgoing(true);

			/*
			 * Default httpIncoming is false;
			 */
			String tcpIncoming = p.getProperty("tcpIncoming");
			if (tcpIncoming != null) {
				netconfig.setTcpIncoming(Boolean.valueOf(tcpIncoming));
			} else {
				netconfig.setTcpIncoming(Boolean.valueOf(false));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void start() {

		try {
			manager.startNetwork();
		} catch (PeerGroupException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		Iterator<CatalogGroupInfo> groups = catalogGroups.iterator();
		while (groups.hasNext()) {
			CatalogGroupInfo groupInfo = groups.next();
			try {

				PeerGroup pg = joinGroupIfExists(groupInfo);

				if (pg == null) {

					manager.getNetPeerGroup().getRendezVousService()
							.startRendezVous();
					System.out.println();
					System.out.println();
					System.out.println("--- AUTOPROMOTING RENDEZVOUS ---");
					System.out.println();
					System.out.println();
					pg = joinGroupIfExists(groupInfo);
				}

				if (pg == null) {
					System.out.println("Cannot find " + groupInfo
							+ " peergroup.");
					System.out.println("Creating " + groupInfo + " peergroup.");

					pg = createPeerGroup(groupInfo.getName());
				}
				RendezVousService rdvSvc = pg.getRendezVousService();
				boolean connected = false;
				System.out.print("Waiting for Rendezvous connection");
				for (int i = 0; i < 20; i++) {
					connected = rdvSvc.isConnectedToRendezVous();
					System.out.print(".");
					Thread.sleep(1500);
					if (connected) {
						System.out.print("Rendezvous found");
						break;
					}
				}
				System.out.println();
				if (!connected) {
					pg.getRendezVousService().startRendezVous();
					System.out
							.println("No Rendezvous found. Promoting to Rendezvous in "
									+ pg.getPeerGroupName());
				}

				if (pg.isRendezvous())
					System.out.println("I'm RDV in " + groupInfo.getName()
							+ " peergroup.");

				Enumeration<ID> rdvEnum = pg.getRendezVousService()
						.getConnectedRendezVous();
				while (rdvEnum.hasMoreElements()) {
					System.out.println("RDV: " + rdvEnum.nextElement().toURI());
					connected = true;
				}

				CatalogPeer c = new CatalogPeer(catalogProps, pg);
				c.init();
				c.start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private PeerGroup createPeerGroup(String groupName) {
		PeerGroup ret = null;
		DiscoveryService disco = manager.getNetPeerGroup()
				.getDiscoveryService();
		try {
			ModuleImplAdvertisement implAdv = manager.getNetPeerGroup()
					.getAllPurposePeerGroupImplAdvertisement();
			ret = manager.getNetPeerGroup().newGroup(
					(PeerGroupID) IDFactory.newPeerGroupID(), implAdv,
					groupName, groupName);

			PeerGroupAdvertisement peerGroupAdv = ret
					.getPeerGroupAdvertisement();
			disco.publish(peerGroupAdv);
			disco.remotePublish(peerGroupAdv);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ret;

	}

	public static void main(String[] args) {

		CatalogLauncher cl = new CatalogLauncher(args);
		cl.start();
	}

}
